#include "StdAfx.h"
#include "RaceController.h"
#include "BoundingVolume.h"
#include "ActionObject.h"
#include "IMovable.h"
#include "RenderableObject.h"
#include "GameController.h"
#include "InputController.h"
#include "PhysicalObject.h"
#include "Gate.h"
#include "CollisionController.h"
#include "MeshStorage.h"
#include "RenderingManager.h"
#include "AIAgent.h"
#include "Race.h"
#include "Countdown.h"
#include "TrackLoader.h"
#include "ThirdPersonCamera.h"
#include "Victory.h"


/////////////////////////////////////////////////////////////////////////////

RaceController::RaceController(IGameController& gameController,
                               IRenderingManager& renderingManager,
                               IMeshStorage& meshStorage,
                               CInputController& inputController,
                               ICameraImpl& cameraImpl)
      : m_collisionController(new CCollisionController()),
      m_gameController(gameController),
      m_renderingManager(renderingManager),
      m_meshStorage(meshStorage),
      m_inputController(inputController),
      m_cameraImpl(cameraImpl),
      m_countdown(NULL),
      m_race(NULL),
      m_victory(NULL),
      m_camera(NULL),
      m_controlledPhysicalObject(NULL),
      m_controlledActionObject(NULL),
      m_gatesToScore(0),
      m_raceInProgress(false),
      m_hasPlayerWon(false)
{
   m_countdown = new Countdown(*this, m_renderingManager, m_meshStorage);
   m_race = new Race(*this, m_activePlayers, m_gates, m_aiAgents);
   m_victory = new Victory(*this, m_renderingManager, m_meshStorage);
}

/////////////////////////////////////////////////////////////////////////////

RaceController::~RaceController()
{
   removeDeadPlayers();

   m_currentState = NULL;

   delete m_countdown;
   m_countdown = NULL;

   delete m_race;
   m_race = NULL;

   delete m_victory;
   m_victory = NULL;

   delete m_collisionController;
   m_collisionController = NULL;
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::update(float timeElapsed)
{
   removeDeadPlayers();

   for (UINT i = 0; i < m_activePlayers.size(); ++i)
   {
      m_activePlayers[i]->update(timeElapsed);
   }

   m_collisionController->update(timeElapsed);

   m_currentState->update(timeElapsed);
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::activate()
{
   m_inputController.setProcessor(*this);

   // load the track we'll be racing on
   TrackLoader trackLoader(*m_collisionController,
                           m_renderingManager,
                           m_meshStorage,
                           *this,
                           *this,
                           m_activePlayers,
                           m_gates,
                           m_aiAgents);
   trackLoader.load(m_gameController.getTrackName());

   // set up the player control
   m_controlledPhysicalObject = trackLoader.getUserControlledPhysicalObject();
   m_controlledActionObject = trackLoader.getUserControlledActionObject();
   m_camera = new CThirdPersonCamera(m_cameraImpl, *(trackLoader.getUserControlledMovable()));
   m_collisionController->addGhost(*m_camera);

   // set up the race states
   m_raceInProgress = false;

   UINT numLapses = 1;
   m_gatesToScore = m_gates.size() / numLapses;

   m_currentState = m_countdown;
   m_currentState->activate();
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::startRace()
{
   m_currentState->deactivate();
   m_currentState = m_race;
   m_raceInProgress = true;
   m_currentState->activate();
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::victory(UINT playerIdx)
{
   m_currentState->deactivate();
   
   m_raceInProgress = false;
   m_hasPlayerWon = (playerIdx == 0);

   m_currentState = m_victory;
   m_currentState->activate();
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::raceOver()
{
   m_currentState->deactivate();
   m_gameController.openMainMenu();
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::deactivate()
{
   m_inputController.resetProcessor();

   while(m_activePlayers.size() > 0)
   {
      removePlayer(m_activePlayers[0]);
   }
   removeDeadPlayers();

   for (UINT i = 0; i < m_gates.size(); ++i)
   {
      delete m_gates[i];
   }
   m_gates.clear();

   if (m_camera != NULL)
   {
      delete m_camera;
      m_camera = NULL;
   }

   m_renderingManager.clearRenderingList();
   m_collisionController->clearScene();
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::processInput(UCHAR* keyBuffer, float timeElapsed)
{
   m_currentState->processInput(keyBuffer, timeElapsed);
}

/////////////////////////////////////////////////////////////////////////////

std::vector<ActionObject*> RaceController::queryForObjects(const Ray& ray)
{
   std::vector<ActionObject*> objects;

   for (UINT i = 0; i < m_activePlayers.size(); ++i)
   {
      IMovable& movable = m_activePlayers[i]->getMovable(); 
      if (movable.getWorldSpaceBoundingBox().isCollidingWith(ray))
      {
         objects.push_back(m_activePlayers[i]);
      }
   }

   return objects;
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::removePlayer(ActionObject* object)
{
   std::vector<ActionObject*>::iterator it = m_activePlayers.begin();
   for (; it != m_activePlayers.end(); ++it)
   {
      if ((void*)(*it) == (void*)object) break;
   }

   if (it != m_activePlayers.end())
   {
      m_deadPlayers.push_back(*it);
      m_activePlayers.erase(it);
   }
}

/////////////////////////////////////////////////////////////////////////////

void RaceController::removeDeadPlayers()
{
   for (UINT i = 0; i < m_deadPlayers.size(); ++i)
   {
      ActionObject* deadPlayer = m_deadPlayers[i];
      m_collisionController->removeMovable(deadPlayer->getMovable());

      for(std::vector<AIAgent*>::iterator aiIt = m_aiAgents.begin(); 
         aiIt != m_aiAgents.end(); ++aiIt)
      {
         if ((void*)(&((*aiIt)->getActionObject())) == (void*)(deadPlayer))
         {
            m_aiAgents.erase(aiIt);
            break;
         }
      }

      delete deadPlayer;
   }
   m_deadPlayers.clear();
}

/////////////////////////////////////////////////////////////////////////////
